home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Magazine / GraphicsCards / Warp3D / Developer / Source / WarpTest.c
C/C++ Source or Header  |  1999-02-04  |  47KB  |  1,596 lines

  1. /*
  2.     WarpTest
  3.     This program is part of the Warp3D project.
  4.     Copyright © 1998 Thomas Frieden, Hans-Jörg Frieden, Sam Jordan
  5.     You may freely modify and/or use any part of this file. It
  6.     is considered an example for programming Warp3D.
  7.  
  8.     This is a small program that shows some effects that can be done
  9.     with Warp3D, and may also serve as an example for programming
  10.     with Warp3D. It demonstrates fog, alpha blending, texture mapping,
  11.     both linear and perspective corrected, gouraud shading, filtering,
  12.     light mapping, mipmapping, including automatic mipmap generation,
  13.     and double buffering. Here`s how to use it:
  14.     From shell, enter WarpTest <texture.ppm>. If the texture is omitted,
  15.     wall.ppm is taken as default.
  16.     The wall can be moved and rotated with the cursor keys. Pressing the
  17.     mouse button and moving the mouse also rotates the wall. You can also
  18.     use the following keys for switching different effects:
  19.  
  20.         f - Toggle fogging.
  21.         8 - Push back the fog end value (observe the second last text row)
  22.         5 - Push fog end towards viewer
  23.         9 - Push back fog start
  24.         6 - Push fog start towards viewer
  25.  
  26.         t - toggle texture mapping/gouraud shading
  27.         e - toggle light mapping
  28.         p - toggle linear/perspective corrected mapping
  29.  
  30.         l - turn on alpha blending
  31.         1 - set filtering to W3D_NEAREST (no texture filtering)
  32.         2 - set filtering to W3D_LINEAR (bilinear texture
  33.         3 - set filtering to W3D_NEAREST_MIP_NEAREST (mipmapping, no filtering)
  34.         4 - set filtering to W3D_LINEAR_MIP_LINEAR (trilinear filtering with
  35.                                                 mipmapping)
  36.  
  37.         a - show mipmaps (don`t mind the flickering, they are only drawn
  38.                                                 to the first buffer)
  39.         b - show vertex coordinates (not very useful)
  40.         c - slow motion
  41.         d - draw the background pattern
  42.  
  43.         Pressing 'a' shows the current texture, along with the mipmaps
  44.         that were automatically created. These mipmaps are created with
  45.         a simple median where four pixels are summed up and divided by
  46.         four to produce a new pixel.
  47.  
  48.     History
  49.     -------
  50.     6-Aug-98        First public developer release
  51.  
  52.     8-Aug-98        Added a background patter switch (red lines), plus a
  53.                     key ('d') to toggle it. Additionally, Opacity for
  54.                     textures was replaced with a gradient pattern running
  55.                     from top-left to bottom-right.
  56.  
  57.     13-Sep-98       ZBuffering now works
  58.     28-Sep-98       Pressing F not switches hinting about fogging (press twice,
  59.                     I wa too lazy to correct the bug :)
  60.      3-Oct-98       Added TEXTURE and ZBUFFER command line switches
  61.     12-Jan-99       Added Outline mode with W3D_DrawLineLoop
  62.                     Added V2 driver interface
  63.                     Increased library minimum version to 2.0
  64.                     Added information printing about drivers
  65.                     Added example for W3D_QueryDriver
  66.  
  67. */
  68. //+ Includes
  69. #include <stdio.h>
  70. #include <stdlib.h>
  71. #include <string.h>
  72. #include <math.h>
  73. #include <exec/types.h>
  74. #include <exec/memory.h>
  75. #include <libraries/asl.h>
  76. #ifndef __PPC__
  77. #include <proto/exec.h>
  78. #include <proto/intuition.h>
  79. #include <proto/cybergraphics.h>
  80. #include <proto/dos.h>
  81. #include <proto/graphics.h>
  82. #else
  83. #include <clib/exec_protos.h>
  84. #include <clib/intuition_protos.h>
  85. #include <clib/cybergraphics_protos.h>
  86. #include <clib/dos_protos.h>
  87. #include <clib/graphics_protos.h>
  88. #include <clib/powerpc_protos.h>
  89. #endif
  90. #ifndef __STORM__
  91. #include <cybergraphx/cybergraphics.h>
  92. #else
  93. #include <cybergraphics/cybergraphics.h>
  94. #endif
  95. #include <Warp3D/Warp3D.h>
  96. #include <clib/Warp3D_protos.h>
  97. #ifndef __PPC__
  98. #ifndef __STORM__
  99. #include <pragmas/Warp3D_pragmas.h>
  100. #else
  101. #include <pragma/Warp3D_lib.h>
  102. #endif
  103. #endif
  104.  
  105. //-
  106. //+ Stuff
  107.  
  108.  
  109.  
  110. #ifdef __STORM__
  111. char version[] = "$VER: WarpTest_StormC 1.1 (6-Aug-98)";
  112. #else
  113. char version[] = "$VER: WarpTest_SAS/C 1.1 (6-Aug-98)";
  114. #endif
  115.  
  116. #ifndef __STORM__
  117. #pragma msg 193 ignore
  118. #pragma msg  93 ignore
  119. #endif
  120.  
  121. #ifndef __PPC__
  122. struct Library *Warp3DBase;
  123. #else
  124. struct Library *Warp3DPPCBase;
  125. #endif
  126. struct Library *CyberGfxBase;
  127. struct Screen *screen;
  128. struct Window *window;
  129. int bufnum = 0;
  130. BOOL outline = FALSE;
  131. BOOL zb = FALSE;
  132.  
  133. struct RDArgs *rda = NULL;
  134. #define TEMPLATE "TEXTURE,ZBUFFER/S,REPEAT/N,LIGHTMAP/K"
  135.  
  136. ULONG texturesize;
  137. UBYTE *texture;
  138. UBYTE *lightmap;
  139. LONG result[10];
  140.  
  141. W3D_Texture *tex, *lighttex = NULL;
  142. W3D_Triangle tri;
  143. W3D_Color ccol = {0.0, 1.0, 0.0, 0.8};
  144. W3D_Double zdepth = 0.8;
  145. ULONG zmode = 0;
  146.  
  147. ULONG DLevel=0, DWrap=0;
  148. int persp = 0;
  149. int forcelin = 0;
  150. float divisor = 2048.0;
  151. float factor = 16.f;
  152. float tmax   = 256.f;
  153. float lastw  = 0.f;
  154. float lastd  = 0.f;
  155. ULONG CurrentBlend = 0;
  156. ULONG BlendModes[] = {W3D_REPLACE, W3D_DECAL, W3D_MODULATE, W3D_BLEND};
  157. ULONG CurrentFog = 0;
  158. ULONG FogModes[] = {0, W3D_FOG_LINEAR, W3D_FOG_EXP, W3D_FOG_EXP_2, W3D_FOG_INTERPOLATED};
  159. W3D_Double LastZ = 0.0;
  160. int curfilt = 1;
  161. int drag = 0;
  162. int push = 0;
  163. int second_wall = 0;
  164.  
  165. const float Back  = 40.0;
  166. const float Front = 0.5;
  167.  
  168. #define kzen (-65535.0*(Back*Front)/(Back-Front))
  169. #define z0   ( 65535.0*Back/(Back-Front))
  170. #define SCALE 240
  171.  
  172. typedef struct {
  173.     float x,y,z;
  174.     float u,v;
  175.     float iz;
  176. } Vector3;
  177.  
  178. typedef struct {
  179.     float m11, m12, m13;
  180.     float m21, m22, m23;
  181.     float m31, m32, m33;
  182. } Matrix3;
  183.  
  184. Vector3 Square[4] = {
  185.     // x     y    z      u      v
  186.     {-1.f,  1.f, 0.f,   0.f,   0.f},
  187.     { 1.f,  1.f, 0.f,   1.f,   0.f},
  188.     { 1.f, -1.f, 0.f,   1.f,   1.f},
  189.     {-1.f, -1.f, 0.f,   0.f,   1.f}
  190. };
  191.  
  192. Vector3 LSquare[4] = {
  193.     // x     y    z      u      v
  194.     {-1.f,  1.f, 0.f,   0.f,   0.f},
  195.     { 1.f,  1.f, 0.f,   1.f,   0.f},
  196.     { 1.f, -1.f, 0.f,   1.f,   1.f},
  197.     {-1.f, -1.f, 0.f,   0.f,   1.f}
  198. };
  199.  
  200.  
  201. Vector3 TempSquare[4];
  202.  
  203. Vector3 Pos = {0.f, 0.f, 3.f, 0.f, 0.f};    // Position of wall
  204. float theta = 0.0;                          // Wall Angle
  205.  
  206. int aflag=0, bflag=0, cflag=0, dflag=0;
  207.  
  208. ULONG FogQuality = W3D_H_NICE;
  209. W3D_Fog myFog = {
  210.     1.0,0.2,1.0,
  211.     {8.1/32.0, 8.1/32.0, 17.1/32.0}
  212. };
  213.  
  214.  
  215. void *texmap;
  216.  
  217. //-
  218. //+ Matrix/Vector stuff
  219. void MatVec(Matrix3 *M, Vector3 *v, Vector3 *r)
  220. {
  221.     // Calcuate r=Mv
  222.     r->x = M->m11*v->x + M->m12*v->y + M->m13*v->z;
  223.     r->y = M->m21*v->x + M->m22*v->y + M->m23*v->z;
  224.     r->z = M->m31*v->x + M->m32*v->y + M->m33*v->z;
  225. }
  226.  
  227. void RotYMat(Matrix3 *M, float theta)
  228. // Create a Y axis rotation matrix by angle theta (theta in degrees)
  229. {
  230.  
  231.     theta = theta/180.f * PI;
  232.  
  233.     M->m11 =  (float)cos(theta);
  234.     M->m13 = -(float)sin(theta);
  235.     M->m31 =  (float)sin(theta);
  236.     M->m33 =  (float)cos(theta);
  237.     M->m22 =  1.f;
  238.  
  239.     M->m12 =
  240.     M->m21 =
  241.     M->m23 =
  242.     M->m32 = 0.f;
  243. }
  244.  
  245. void Project(Vector3 *v)
  246. {
  247.     if (v->z == 0.f) v->z+=0.0001;
  248.     v->iz = 1.0/v->z;
  249.     v->x = 320+SCALE*v->x*(v->iz);
  250.     v->y = 240-SCALE*v->y*(v->iz);
  251.     v->z = ((kzen/v->z)+z0)/65536.f;
  252. }
  253.  
  254. void VecAdd(Vector3 *a, Vector3 *b, Vector3 *r)
  255. // Calcuate r=a+b;
  256. // I love C++!!!
  257. {
  258.     r->x = a->x + b->x;
  259.     r->y = a->y + b->y;
  260.     r->z = a->z + b->z;
  261. }
  262.  
  263. void Transform(Vector3 Pos, float theta)
  264. // Transform the wall to the desired orientation
  265. {
  266.     Matrix3 M;
  267.     Vector3 r;
  268.     int i;
  269.  
  270.     RotYMat(&M, theta);     // Create rotation matrix;
  271.     for (i=0; i<4; i++) {
  272.         MatVec(&M, &Square[i], &TempSquare[i]);
  273.         VecAdd(&TempSquare[i], &Pos, &TempSquare[i]);
  274.     //}
  275.     //for (i=0; i<4; i++) {
  276.         Project(&TempSquare[i]);
  277.     }
  278. }
  279. //-
  280. //+ "LoadTextureFromPPM"
  281. #define ARGB8888toARGB1555(ic) (0x8000 | ((ic&0xF8)>>3) | ((ic&0xF800)>>6) | ((ic&0xF80000)>>9))
  282. #define ARGB8888toARGB4444(ic) ((ic&0xF0000000)>>16 | \
  283.                                 (ic&0x00F00000)>>12 | \
  284.                                 (ic&0x0000F000)>>8  | \
  285.                                 (ic&0x000000F0)>>4)
  286. UBYTE *LoadTextureFromPPM(APTR where, char *filename, UBYTE Opacity, int *w, int *h)
  287. {
  288.     ULONG *map, *map2;
  289.     FILE *f;
  290.     int i,j;
  291.     UBYTE r,g,b;
  292.     UWORD a;
  293.     unsigned long x,y;
  294.     int opqy, opqx, o;
  295.  
  296.     f=fopen(filename, "r");
  297.  
  298.     if (!f) {
  299.         printf("Error: Unable to open file '%s'\n", filename);
  300.         return NULL;
  301.     }
  302.  
  303. #ifndef __STORM__
  304.     i=fscanf(f, "P6\n%ld %ld\n255\n", &x, &y);
  305. #else
  306.     i=fscanf(f, "P6\n%ld\n%ld\n255\n", &x, &y);
  307. #endif
  308.  
  309.     if (i!=2) {
  310.         printf("Error: This seems to be no PPM file\n");
  311.         fclose(f);
  312.         return NULL;
  313.     }
  314.  
  315.     *w = x;
  316.     *h = y;
  317.  
  318.     if (where==NULL) {
  319.         map2 = map = AllocVec(x*y*4, MEMF_PUBLIC);
  320.     } else {
  321.         map = map2 = where;
  322.     }
  323.     if (!map) {
  324.         fclose(f);
  325.         printf("Error: Out of memory\n");
  326.         return NULL;
  327.     }
  328.  
  329.     opqy = 256/y;
  330.     opqx = 256/x;
  331.     opqx = opqx>>1;
  332.     o=0;
  333.     for (i=0; i<y; i++) {
  334.         for(j=0; j<x; j++) {
  335.             if (o+j*opqy > 255)
  336.                 Opacity = 255;
  337.             else
  338.                 Opacity = (UBYTE)(o+j*opqy);
  339.  
  340.             r=(UBYTE)fgetc(f);
  341.             g=(UBYTE)fgetc(f);
  342.             b=(UBYTE)fgetc(f);
  343.             *map = (Opacity<<24) | ((r&0xFF)<<16) | ((g&0xFF)<<8) | (b&0xFF);
  344. //            *map = (Opacity<<8) | ((r&0xFF)) | ((g&0xFF)<<24) | (b&0xFF)<<16;
  345.             map++;
  346.         }
  347.         o += opqx;
  348.     }
  349.  
  350.     fclose(f);
  351.     return (UBYTE *)map2;
  352. }
  353. //-
  354. //+ GenTexture
  355. int log2(int x)
  356. {
  357.     // Kludgy but fast :)
  358.     // floats are too small for log(x)/log(2)...
  359.     switch(x) {
  360.     case 65536: return 16;
  361.     case 32768: return 15;
  362.     case 16384: return 14;
  363.     case 8192: return 13;
  364.     case 4096: return 12;
  365.     case 2048: return 11;
  366.     case 1024: return 10;
  367.     case 512: return 9;
  368.     case 256: return 8;
  369.     case 128: return 7;
  370.     case 64:  return 6;
  371.     case 32:  return 5;
  372.     case 16:  return 4;
  373.     case 8:   return 3;
  374.     case 4:   return 2;
  375.     case 2:   return 1;
  376.     case 1:   return 0;
  377.     }
  378. }
  379.  
  380. BOOL GenTexture(W3D_Context* context, char* name, LONG repeat)
  381. {
  382.     UBYTE *where;
  383.     int w, h;
  384.     ULONG error;
  385.     int maps,i;
  386.  
  387.     // This loads a ppm (24 bit) texture file from disk, and sets
  388.     // it to 50% transparency (0x7F)...
  389.     where = LoadTextureFromPPM(NULL, name, 0x7F, &w, &h);
  390.     if (!where) return FALSE;
  391.     printf("Size: %ld×%ld\n", w,h);
  392.  
  393.     // This sets the square's texture coordinates to the right pixel values
  394.     for (i=0;i<4; i++) {
  395.         Square[i].u *= (w-1);      //  -1
  396.         Square[i].v *= (h-1);      //  -1
  397.         if (repeat > 1) {
  398.             Square[i].u *= repeat;
  399.             Square[i].v *= repeat;
  400.         }
  401.     }
  402.  
  403.  
  404.     texmap = where;
  405.  
  406.     tex = W3D_AllocTexObjTags(context, &error,
  407.         W3D_ATO_IMAGE,      where,          // The image data
  408.         W3D_ATO_FORMAT,     W3D_A8R8G8B8,   // This is a 32 bit image
  409.         W3D_ATO_WIDTH,      w,           // Length of one side
  410.         W3D_ATO_HEIGHT,     h,
  411.         W3D_ATO_MIPMAP,     0xffff,    // Mipmap mask - see autodocs
  412.     TAG_DONE);
  413.  
  414.     if (!tex || error != W3D_SUCCESS) {
  415.         printf("Error generating texture: ");
  416.         switch(error) {
  417.         case W3D_ILLEGALINPUT:
  418.             printf("Illegal input\n");
  419.             break;
  420.         case W3D_NOMEMORY:
  421.             printf("Out of memory\n");
  422.             break;
  423.         case W3D_UNSUPPORTEDTEXSIZE:
  424.             printf("Unsupported texture size\n");
  425.             break;
  426.         case W3D_NOPALETTE:
  427.             printf("Chunky texture without palette specified\n");
  428.             break;
  429.         case W3D_UNSUPPORTEDTEXFMT:
  430.             printf("Texture format not supported\n");
  431.             break;
  432.         default:
  433.             printf("ahem... An error has occured\n");
  434.         }
  435.         return FALSE;
  436.     }
  437.     return TRUE;
  438. }
  439. //-
  440. //+ GenLightmap
  441. // Ok, this is a cheap, but who cares :)
  442. // In a real application, you would have this code only once
  443. BOOL GenLightmap(W3D_Context* context, char* name, LONG repeat)
  444. {
  445. #define LEVEL a
  446.     UBYTE *where, *here;
  447.     int w, h;
  448.     ULONG error;
  449.     int maps,i;
  450.     int a;
  451.  
  452.     // This loads a ppm (24 bit) texture file from disk, and sets
  453.     // it to 50% transparency (0x7F)...
  454.     where = LoadTextureFromPPM(NULL, name, 0x7F, &w, &h);
  455.     if (!where) return FALSE;
  456.     printf("Size: %ld×%ld\n", w,h);
  457.  
  458.     // Convert it to pure alpha
  459.     // Should really use a W3D_A8 here, but I'm too lazy
  460.     here = where;
  461.     for (i = 0; i < w*h; i++) {
  462.         a = (here[1] + here[2] + here[3])/3;
  463.         here[0] = a;
  464.         here[1] = LEVEL;
  465.         here[2] = LEVEL;
  466.         here[3] = LEVEL;
  467.         here += 4;
  468.     }
  469.  
  470.  
  471.     // This sets the square's texture coordinates to the right pixel values
  472.     for (i=0;i<4; i++) {
  473.         LSquare[i].u *= (w-1);      //  -1
  474.         LSquare[i].v *= (h-1);      //  -1
  475.         if (repeat > 1) {
  476.             LSquare[i].u *= repeat;
  477.             LSquare[i].v *= repeat;
  478.         }
  479.     }
  480.  
  481.  
  482.     lightmap = where;
  483.  
  484.     lighttex = W3D_AllocTexObjTags(context, &error,
  485.         W3D_ATO_IMAGE,      where,          // The image data
  486.         W3D_ATO_FORMAT,     W3D_A8R8G8B8,   // This is a 32 bit image
  487.         W3D_ATO_WIDTH,      w,           // Length of one side
  488.         W3D_ATO_HEIGHT,     h,
  489.         W3D_ATO_MIPMAP,     0xffff,    // Mipmap mask - see autodocs
  490.     TAG_DONE);
  491.  
  492.     if (!tex || error != W3D_SUCCESS) {
  493.         printf("Error generating light texture: ");
  494.         switch(error) {
  495.         case W3D_ILLEGALINPUT:
  496.             printf("Illegal input\n");
  497.             break;
  498.         case W3D_NOMEMORY:
  499.             printf("Out of memory\n");
  500.             break;
  501.         case W3D_UNSUPPORTEDTEXSIZE:
  502.             printf("Unsupported texture size\n");
  503.             break;
  504.         case W3D_NOPALETTE:
  505.             printf("Chunky texture without palette specified\n");
  506.             break;
  507.         case W3D_UNSUPPORTEDTEXFMT:
  508.             printf("Texture format not supported\n");
  509.             break;
  510.         default:
  511.             printf("ahem... An error has occured\n");
  512.         }
  513.         return FALSE;
  514.     }
  515.     return TRUE;
  516. }
  517. //-
  518. //+ PrintInfo
  519. void PrintInfo(W3D_Context* context)
  520. {
  521.     int x,y;
  522.     static char buffer[256];
  523.  
  524.     SetAPen(window->RPort, 2);
  525.     SetDrMd(window->RPort, JAM1);
  526.     x=450; y=100;
  527.     if (bufnum == 0)    y += 480;
  528.  
  529.     if (W3D_GetState(context, W3D_FAST) == W3D_ENABLED)
  530.                        sprintf(buffer, "Fast mode");
  531.     else               sprintf(buffer, " ");
  532.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  533.  
  534.     if (outline)       sprintf(buffer, "Outline mode");
  535.     else               sprintf(buffer, " ");
  536.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  537.  
  538.     if (aflag)         sprintf(buffer, "Show MipMaps");
  539.     else               sprintf(buffer, " ");
  540.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  541.  
  542.     if (bflag)         sprintf(buffer, "Vertex coordinates");
  543.     else               sprintf(buffer, " ");
  544.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  545.  
  546.     if (cflag)         sprintf(buffer, "Slow motion");
  547.     else               sprintf(buffer, " ");
  548.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  549.  
  550.     if (W3D_GetState(context, W3D_PERSPECTIVE) == W3D_ENABLED)
  551.         sprintf(buffer, "Perspective");
  552.     else
  553.         sprintf(buffer, "Linear");
  554.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  555.  
  556.     if (W3D_GetState(context,W3D_TEXMAPPING) == W3D_ENABLED)
  557.         sprintf(buffer, "Texture Mapping");
  558.     else
  559.         sprintf(buffer, "Gouraud Shading");
  560.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  561.  
  562.     switch(CurrentBlend) {
  563.     case 0:
  564.         sprintf(buffer, "Blend REPLACE");
  565.         break;
  566.     case 1:
  567.         sprintf(buffer, "Blend DECAL");
  568.         break;
  569.     case 2:
  570.         sprintf(buffer, "Blend MODULATE");
  571.         break;
  572.     case 3:
  573.         sprintf(buffer, "Blend BLEND");
  574.         break;
  575.     default:
  576.         sprintf(buffer, "Blend UNKNOWN");
  577.     }
  578.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  579.  
  580.     sprintf(buffer, "theta=%3.1f", theta);
  581.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  582.  
  583.     sprintf(buffer, "pos=(%3.1f %3.1f %3.1f)", Pos.x, Pos.y, Pos.z);
  584.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  585.  
  586.     sprintf(buffer, "Z-Clipping Plane %3.2f", zdepth);
  587.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  588.     {
  589.         char *zm;
  590.         switch(zmode) {
  591.         case 0:             zm = "Z-Buffer disabled";   break;
  592.         case W3D_Z_NEVER:   zm = "Z-Buffer never pass"; break;
  593.         case W3D_Z_LESS:    zm = "Z-Buffer less";       break;
  594.         case W3D_Z_GEQUAL:  zm = "Z-Buffer greater/equal"; break;
  595.         case W3D_Z_LEQUAL:  zm = "Z-Buffer less/equal"; break;
  596.         case W3D_Z_GREATER: zm = "Z-Buffer greater";    break;
  597.         case W3D_Z_NOTEQUAL:zm = "Z-Buffer not equal";  break;
  598.         case W3D_Z_EQUAL:   zm = "Z-Buffer equal";      break;
  599.         case W3D_Z_ALWAYS:  zm = "Z-Buffer always pass";break;
  600.         default:            zm = "??? Unknown Z-Mode";  break;
  601.         }
  602.         Move(window->RPort, x,y); Text(window->RPort, zm, strlen(zm)); y+=14;
  603.     }
  604.  
  605.     sprintf(buffer, "Last Z: %3.2f", LastZ);
  606.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  607.  
  608.     if (W3D_GetState(context,W3D_BLENDING) == W3D_ENABLED)
  609.         sprintf(buffer, "Alpha Blending");
  610.     else
  611.         sprintf(buffer, "No Blending");
  612.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  613.  
  614.     switch (CurrentFog) {
  615.         case 0: sprintf(buffer, "Fog off");             break;
  616.         case 1: sprintf(buffer, "Fog linear");          break;
  617.         case 2: sprintf(buffer, "Fog exponential");     break;
  618.         case 3: sprintf(buffer, "Fog exponential 2");   break;
  619.         case 4: sprintf(buffer, "Fog interpolated");    break;
  620.     }
  621.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  622.  
  623.     sprintf(buffer, "(%3.2f - %3.2f)",
  624.         context->fog.fog_start, context->fog.fog_end);
  625.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  626.  
  627.     switch(curfilt) {
  628.         case 1: sprintf(buffer, "W3D_NEAREST"); break;
  629.         case 2: sprintf(buffer, "W3D_LINEAR"); break;
  630.         case 3: sprintf(buffer, "W3D_NEAREST_MIP_NEAREST"); break;
  631.         case 4: sprintf(buffer, "W3D_LINEAR_MIP_LINEAR"); break;
  632.     }
  633.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  634.  
  635.     y=430; if (bufnum == 0) y+=480;
  636.     x=10;
  637.  
  638.     sprintf(buffer, "A - Mipmap view  B - Vertex coords  C - Slow Motion  P - Perspective Mapping");
  639.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  640.     sprintf(buffer, "T - Texture Mapping  F - Fogging  L - Alpha  1..4 - Filter");
  641.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  642.     sprintf(buffer, "E - Blendmode  ESC - Quit");
  643.     Move(window->RPort, x,y); Text(window->RPort, buffer, strlen(buffer)); y+=14;
  644.  
  645. }
  646. //-
  647. //+ ClearWindow
  648. void ClearWindow(W3D_Context *context,struct Window *window)
  649. {
  650. /*
  651.     This clears the window using a plain simple rectfill.
  652.     Note that it does many things with the texture handle,
  653.     which is not really illegal as long as you don't write
  654.     directly to the texture handle...
  655. */
  656.     UWORD *t = tex->texdest;
  657.     int i,j,k;
  658.     int w = tex->texwidth;
  659.     int h = tex->texheight;
  660.     EraseRect(window->RPort, 0, (1-bufnum) * 480, 639, (1-bufnum) * 480 + 479);
  661.     if (dflag) {
  662.         int blah = (1-bufnum)*480;
  663.         SetAPen(window->RPort,10);
  664.         for (i=30; i<480; i+=30) {
  665.             Move(window->RPort, 0, i+blah);
  666.             Draw(window->RPort, 639, i+blah);
  667.         }
  668.         for (i=30; i<640; i+=30) {
  669.             Move(window->RPort, i, blah);
  670.             Draw(window->RPort, i, blah+479);
  671.         }
  672.     }
  673.     if (aflag) {
  674.         // If AFlag is set, draw the mipmap
  675.         WritePixelArray(tex->texsource, 0,0, w*4,
  676.             window->RPort, 0,(1-bufnum)*480, w,h, RECTFMT_ARGB);
  677.         if (w>h) {
  678.             j = w/2;
  679.             k = w;
  680.         } else{
  681.             j = h/2;
  682.             k = w;
  683.         }
  684.  
  685.         i=0;
  686.         while (j) {
  687.             WritePixelArray(tex->mipmaps[i++],0,0,w*2,
  688.                 window->RPort,
  689.                 k,(1-bufnum)*480, w/2,h/2, RECTFMT_ARGB);
  690.             k+=w/2;
  691.             j/=2;
  692.             w/=2; if (w == 0) w = 1;
  693.             h/=2; if (h == 0) h = 1;
  694.         }
  695.     }
  696.     PrintInfo(context);
  697. }
  698. //-
  699. //+ DrawWall
  700. void DrawWall(W3D_Context *context)
  701. {
  702.     static char buffer[512];
  703.     int i;
  704.  
  705.     Transform(Pos, theta);    // Do the perspective transformations
  706.  
  707.     tri.tex = tex;  // Set the texture handle
  708.  
  709.    /*
  710.     A few notes about the triangle structure:
  711.  
  712.     The "x" and "y" components are pretty obvious. They specify the screen
  713.     coordinates of the corresponding vertex (as a float; this gives you
  714.     sub-pixel accuracy, which is especially useful for small triangles).
  715.  
  716.     The "z" component is the depth of the vertex. 0.0 means this vertex
  717.     sticks to the glass of your monitor (i.e. is closest to the front
  718.     clipping plane), while 1.0 means that the vertex is far away. The "z"
  719.     component is used for Z-Buffering, and, depending on the driver, might
  720.     be used for fogging as well
  721.  
  722.     "u" and "v" are the texture coordinates on this vertex, expressed
  723.     as pixels on the map. Note that this conforms with the OpenGL notion
  724.     of "u" and "v". "u" and "v" are not to be confused with OpenGL's
  725.     "s" and "t", which are in the range [0..1].
  726.  
  727.     color is the vertex color if lighting is used. Note that the alpha
  728.     value might or might not be used, depending on the blending mode.
  729.     The ViRGE implementation ignores this value, since the vertex alpha
  730.     is required for fogging.
  731.  
  732.     Note however, that the texture alpha is always taken into account (if
  733.     the required blending mode is selected)
  734.     */
  735.  
  736.     tri.v1.x = TempSquare[3].x; tri.v1.y = TempSquare[3].y; tri.v1.z = TempSquare[3].z;
  737.     tri.v1.w = TempSquare[3].iz;        //1.f-tri.v1.z;
  738.     tri.v1.u = Square[3].u;     tri.v1.v = Square[3].v;
  739.     tri.v1.color.r = 1.0; tri.v1.color.g = 1.0; tri.v1.color.b = 1.0; tri.v1.color.a = 1.0;
  740.  
  741.     tri.v2.x = TempSquare[1].x; tri.v2.y = TempSquare[1].y; tri.v2.z = TempSquare[1].z;
  742.     tri.v2.w = TempSquare[1].iz;        //1.f-tri.v2.z;
  743.     tri.v2.u = Square[1].u;     tri.v2.v = Square[1].v;
  744.     tri.v2.color.r = 1.0; tri.v2.color.g = 0.0; tri.v2.color.b = 0.0; tri.v2.color.a = 0.5;
  745.  
  746.     tri.v3.x = TempSquare[0].x; tri.v3.y = TempSquare[0].y; tri.v3.z = TempSquare[0].z;
  747.     tri.v3.w = TempSquare[0].iz;        //1.f-tri.v3.z;
  748.     tri.v3.u = Square[0].u;     tri.v3.v = Square[0].v;
  749.     tri.v3.color.r = 1.0; tri.v3.color.g = 1.0; tri.v3.color.b = 0.1; tri.v3.color.a = 1.0;
  750.  
  751.     // You must lock the hardware prior to drawing anything.
  752.     // Note that AUTOLOCKING, if enabled, will do this for you,
  753.     // but it is strictly recommended that you do locking yourself,
  754.     // since performance will suffer if you lock the hardware for
  755.     // every triangle. It is more efficient to lock hardware once for
  756.     // a few triangles, for example, for one polygon.
  757.     //
  758.     // NOTE 2: The CyberGfx implementation of the graphic sub-system
  759.     // driver uses LockBitmap() for this, so you may not hold the
  760.     // lock longer than one display frame (i.e. for a short time)
  761.     if (W3D_SUCCESS != W3D_LockHardware(context)) {
  762. //        printf("Error: Can`t lock hardware\n");
  763.         return;
  764.     }
  765.  
  766.     // Go ahead and fire off the first triangle.
  767.     W3D_DrawTriangle(context, &tri);
  768.  
  769.     // Fill in the triangle structure again.
  770.     tri.v1.x = TempSquare[1].x; tri.v1.y = TempSquare[1].y; tri.v1.z = TempSquare[1].z;
  771.     tri.v1.w = TempSquare[1].iz;        //1.f-tri.v1.z;
  772.     tri.v1.u = Square[1].u;     tri.v1.v = Square[1].v;
  773.  
  774.     tri.v2.x = TempSquare[2].x; tri.v2.y = TempSquare[2].y; tri.v2.z = TempSquare[2].z;
  775.     tri.v2.w = TempSquare[2].iz;        //1.f-tri.v2.z;
  776.     tri.v2.u = Square[2].u;     tri.v2.v = Square[2].v;
  777.  
  778.     tri.v3.x = TempSquare[3].x; tri.v3.y = TempSquare[3].y; tri.v3.z = TempSquare[3].z;
  779.     tri.v3.w = TempSquare[3].iz;        //1.f-tri.v3.z;
  780.     tri.v3.u = Square[3].u;     tri.v3.v = Square[3].v;
  781.  
  782.     tri.v1.color.r = 1.0; tri.v1.color.g = 0.0; tri.v1.color.b = 0.0; tri.v1.color.a = 0.5;
  783.     tri.v2.color.r = 0.0; tri.v2.color.g = 0.0; tri.v2.color.b = 1.0; tri.v2.color.a = 0.1;
  784.     tri.v3.color.r = 1.0; tri.v3.color.g = 1.0; tri.v3.color.b = 1.0; tri.v3.color.a = 1.0;
  785.  
  786.     // Fire off the second triangle. Note that the drawing routines
  787.     // will wait before writing the values to the registers, but
  788.     // if the W3D_SYNCHRON state is not set, it will return immediately
  789.     // and not wait for completion of the operation. In this case
  790.     // it is your duty to wait until the hardware is idle again.
  791.     W3D_DrawTriangle(context, &tri);
  792.  
  793.     if (result[3]) {
  794.         ULONG Blend;
  795.         W3D_SetBlendMode(context, W3D_SRC_ALPHA, W3D_ONE_MINUS_SRC_ALPHA);
  796.  
  797.         Blend = W3D_GetState(context, W3D_BLENDING);
  798.         W3D_SetState(context, W3D_BLENDING, W3D_ENABLE);
  799.  
  800.         tri.tex = lighttex;  // Set the texture handle
  801.         tri.v1.x = TempSquare[3].x; tri.v1.y = TempSquare[3].y; tri.v1.z = TempSquare[3].z;
  802.         tri.v1.w = TempSquare[3].iz;        //1.f-tri.v1.z;
  803.         tri.v1.u = LSquare[3].u;     tri.v1.v = LSquare[3].v;
  804.         tri.v1.color.r = 1.0; tri.v1.color.g = 1.0; tri.v1.color.b = 1.0; tri.v1.color.a = 1.0;
  805.  
  806.         tri.v2.x = TempSquare[1].x; tri.v2.y = TempSquare[1].y; tri.v2.z = TempSquare[1].z;
  807.         tri.v2.w = TempSquare[1].iz;        //1.f-tri.v2.z;
  808.         tri.v2.u = LSquare[1].u;     tri.v2.v = LSquare[1].v;
  809.         tri.v2.color.r = 1.0; tri.v2.color.g = 1.0; tri.v2.color.b = 1.0; tri.v2.color.a = 1.0;
  810.  
  811.         tri.v3.x = TempSquare[0].x; tri.v3.y = TempSquare[0].y; tri.v3.z = TempSquare[0].z;
  812.         tri.v3.w = TempSquare[0].iz;        //1.f-tri.v3.z;
  813.         tri.v3.u = LSquare[0].u;     tri.v3.v = LSquare[0].v;
  814.         tri.v3.color.r = 1.0; tri.v3.color.g = 1.0; tri.v3.color.b = 1.0; tri.v3.color.a = 1.0;
  815.  
  816.         W3D_DrawTriangle(context, &tri);
  817.  
  818.         tri.v1.x = TempSquare[1].x; tri.v1.y = TempSquare[1].y; tri.v1.z = TempSquare[1].z;
  819.         tri.v1.w = TempSquare[1].iz;        //1.f-tri.v1.z;
  820.         tri.v1.u = LSquare[1].u;     tri.v1.v = LSquare[1].v;
  821.  
  822.         tri.v2.x = TempSquare[2].x; tri.v2.y = TempSquare[2].y; tri.v2.z = TempSquare[2].z;
  823.         tri.v2.w = TempSquare[2].iz;        //1.f-tri.v2.z;
  824.         tri.v2.u = LSquare[2].u;     tri.v2.v = LSquare[2].v;
  825.  
  826.         tri.v3.x = TempSquare[3].x; tri.v3.y = TempSquare[3].y; tri.v3.z = TempSquare[3].z;
  827.         tri.v3.w = TempSquare[3].iz;        //1.f-tri.v3.z;
  828.         tri.v3.u = LSquare[3].u;     tri.v3.v = LSquare[3].v;
  829.  
  830.         tri.v1.color.r = 1.0; tri.v1.color.g = 1.0; tri.v1.color.b = 1.0; tri.v1.color.a = 1.0;
  831.         tri.v2.color.r = 1.0; tri.v2.color.g = 1.0; tri.v2.color.b = 1.0; tri.v2.color.a = 1.0;
  832.         tri.v3.color.r = 1.0; tri.v3.color.g = 1.0; tri.v3.color.b = 1.0; tri.v3.color.a = 1.0;
  833.  
  834.         W3D_DrawTriangle(context, &tri);
  835.         W3D_SetState(context, W3D_BLENDING, Blend);
  836.     }
  837.  
  838.  
  839.     if (outline) {
  840.         static W3D_Color col[4] = {
  841.             {0.9, 0.9, 0.0, 1.0},
  842.             {0.9, 0.0, 0.1, 0.2},
  843.             {0.0, 0.0, 0.9, 0.5},
  844.             {0.9, 0.9, 0.9, 1.0}
  845.         };
  846.         static W3D_Lines temp;
  847.         static W3D_Vertex v[4];
  848.         for(i = 0; i < 4; i++) {
  849.             v[i].x = TempSquare[i].x;
  850.             v[i].y = TempSquare[i].y;
  851.             v[i].z = TempSquare[i].z;    //  Needed for zbuffer
  852.             v[i].w = TempSquare[i].iz;   //  Needed for fogging
  853.             v[i].color.r = col[i].r;
  854.             v[i].color.g = col[i].g;
  855.             v[i].color.b = col[i].b;
  856.             v[i].color.a = col[i].a;
  857.         }
  858.         temp.v = v;
  859.         temp.vertexcount = 4;
  860.         W3D_DrawLineLoop(context, &temp);
  861.     }
  862.  
  863.     if (second_wall) {
  864.         float t2;
  865.  
  866.         t2 = 360.0 - theta;
  867.         if (t2 < 0) t2 = 360.0 - t2;
  868.  
  869.         Transform(Pos, t2);    // Do the perspective transformations
  870.  
  871.         tri.tex = tex;  // Set the texture handle
  872.  
  873.         tri.v1.x = TempSquare[3].x; tri.v1.y = TempSquare[3].y; tri.v1.z = TempSquare[3].z;
  874.         tri.v1.w = TempSquare[3].iz;        //1.f-tri.v1.z;
  875.         tri.v1.u = Square[3].u;     tri.v1.v = Square[3].v;
  876.         tri.v1.color.r = 1.0; tri.v1.color.g = 1.0; tri.v1.color.b = 1.0; tri.v1.color.a = 1.0;
  877.  
  878.         tri.v2.x = TempSquare[1].x; tri.v2.y = TempSquare[1].y; tri.v2.z = TempSquare[1].z;
  879.         tri.v2.w = TempSquare[1].iz;        //1.f-tri.v2.z;
  880.         tri.v2.u = Square[1].u;     tri.v2.v = Square[1].v;
  881.         tri.v2.color.r = 1.0; tri.v2.color.g = 0.0; tri.v2.color.b = 0.0; tri.v2.color.a = 1.0;
  882.  
  883.         tri.v3.x = TempSquare[0].x; tri.v3.y = TempSquare[0].y; tri.v3.z = TempSquare[0].z;
  884.         tri.v3.w = TempSquare[0].iz;        //1.f-tri.v3.z;
  885.         tri.v3.u = Square[0].u;     tri.v3.v = Square[0].v;
  886.         tri.v3.color.r = 1.0; tri.v3.color.g = 1.0; tri.v3.color.b = 0.0; tri.v3.color.a = 1.0;
  887.  
  888.         // Go ahead and fire off the first triangle.
  889.         W3D_DrawTriangle(context, &tri);
  890.  
  891.         // Fill in the triangle structure again.
  892.         tri.v1.x = TempSquare[1].x; tri.v1.y = TempSquare[1].y; tri.v1.z = TempSquare[1].z;
  893.         tri.v1.w = TempSquare[1].iz;        //1.f-tri.v1.z;
  894.         tri.v1.u = Square[1].u;     tri.v1.v = Square[1].v;
  895.  
  896.         tri.v2.x = TempSquare[2].x; tri.v2.y = TempSquare[2].y; tri.v2.z = TempSquare[2].z;
  897.         tri.v2.w = TempSquare[2].iz;        //1.f-tri.v2.z;
  898.         tri.v2.u = Square[2].u;     tri.v2.v = Square[2].v;
  899.  
  900.         tri.v3.x = TempSquare[3].x; tri.v3.y = TempSquare[3].y; tri.v3.z = TempSquare[3].z;
  901.         tri.v3.w = TempSquare[3].iz;        //1.f-tri.v3.z;
  902.         tri.v3.u = Square[3].u;     tri.v3.v = Square[3].v;
  903.  
  904.         tri.v1.color.r = 1.0; tri.v1.color.g = 0.0; tri.v1.color.b = 0.0; tri.v1.color.a = 1.0;
  905.         tri.v2.color.r = 0.0; tri.v2.color.g = 0.0; tri.v2.color.b = 1.0; tri.v2.color.a = 1.0;
  906.         tri.v3.color.r = 1.0; tri.v3.color.g = 1.0; tri.v3.color.b = 1.0; tri.v3.color.a = 1.0;
  907.  
  908.         // Fire off the second triangle. Note that the drawing routines
  909.         // will wait before writing the values to the registers, but
  910.         // if the W3D_SYNCHRON state is not set, it will return immediately
  911.         // and not wait for completion of the operation. In this case
  912.         // it is your duty to wait until the hardware is idle again.
  913.         W3D_DrawTriangle(context, &tri);
  914.  
  915.         if (outline) {
  916.             W3D_Color col[4] = {
  917.                 {0.9, 0.9, 0.0, 1.0},
  918.                 {0.9, 0.0, 0.0, 1.0},
  919.                 {0.0, 0.0, 0.9, 1.0},
  920.                 {0.9, 0.9, 0.9, 1.0}
  921.             };
  922.             W3D_Line temp;
  923.             temp.v1.color.a = 1.0;
  924.             temp.v2.color.a = 0.2;
  925.  
  926.             for(i = 0; i < 4; i++) {
  927.                 temp.v1.x = TempSquare[i].x;
  928.                 temp.v1.y = TempSquare[i].y;
  929.                 temp.v1.z = TempSquare[i].z;    //  Needed for zbuffer
  930.                 temp.v1.w = TempSquare[i].iz;   //  Needed for fogging
  931.                 temp.v2.x = TempSquare[(i+1)%4].x;
  932.                 temp.v2.y = TempSquare[(i+1)%4].y;
  933.                 temp.v2.z = TempSquare[(i+1)%4].z;
  934.                 temp.v2.w = TempSquare[(i+1)%4].iz;
  935.                 temp.v1.color.r = col[i].r;
  936.                 temp.v1.color.g = col[i].g;
  937.                 temp.v1.color.b = col[i].b;
  938.                 temp.v2.color.r = col[(i+1)%4].r;
  939.                 temp.v2.color.g = col[(i+1)%4].g;
  940.                 temp.v2.color.b = col[(i+1)%4].b;
  941.                 W3D_DrawLine(context, &temp);
  942.             }
  943.         }
  944.  
  945.     }
  946.     W3D_UnLockHardware(context);
  947.  
  948.     SetAPen(window->RPort, 249);
  949.     RectFill(window->RPort, 638,0,639,1);
  950.  
  951.     // If the user flipped the bflag on, draw the coordinates at the
  952.     // polygon vertices
  953.     if (bflag) {
  954.         SetAPen(window->RPort, 255);
  955.         for (i=0; i<4; i++) {
  956. #ifndef __STORM__
  957.             Move(window->RPort,(long)TempSquare[i].x, (long)TempSquare[i].y+(1-bufnum)*480);
  958.             sprintf(buffer, "%3.2f,%3.2f", TempSquare[i].z, TempSquare[i].iz);
  959.             Text(window->RPort, buffer, strlen(buffer));
  960. #else           /* compiler bug workaround */
  961.             float temp, temp2;
  962.  
  963.             temp = TempSquare[i].iz;
  964.             temp2 = TempSquare[i].z;
  965.             Move(window->RPort,(long)TempSquare[i].x, (long)TempSquare[i].y+(1-bufnum)*480);
  966.             sprintf(buffer, "%3.2f,%3.2f", temp2, temp);
  967.             Text(window->RPort, buffer, strlen(buffer));
  968. #endif
  969.         }
  970.     }
  971. }
  972.  
  973. //-
  974. //+ dummy
  975. void dummy(void)
  976. {
  977.     volatile int dont_optimize_me_away;
  978.     return;
  979. }
  980. //-
  981. //+ SwitchBuffer
  982. void SwitchBuffer(W3D_Context *context, struct BitMap *bm, struct Screen *scr, BOOL clip)
  983. {
  984.     W3D_Scissor s = {0, 0, 640, 480};
  985.     struct ViewPort *vp = &(scr->ViewPort);
  986.  
  987.     if (clip) {
  988.         s.left = 10;
  989.         s.top = 20;
  990.         s.width = 400;
  991.         s.height = 300;
  992.     }
  993.  
  994.     if (bufnum == 0) {
  995.         W3D_SetDrawRegion(context, bm, 0, &s);
  996.         vp->RasInfo->RyOffset = 480;
  997.         ScrollVPort(vp);
  998.         WaitBOVP(vp);
  999.         bufnum = 1-bufnum;
  1000.         if (clip)   W3D_SetScissor(context, &s);
  1001.     } else {
  1002.         W3D_SetDrawRegion(context, bm, 480, &s);
  1003.         vp->RasInfo->RyOffset = 0;
  1004.         ScrollVPort(vp);
  1005.         WaitBOVP(vp);
  1006.         bufnum = 1-bufnum;
  1007.         if (clip)   W3D_SetScissor(context, &s);
  1008.     }
  1009.  
  1010. }
  1011. //-
  1012. //+ PrintDriverInfo
  1013. void PrintDriverInfo(void)
  1014. {
  1015.     ULONG res;
  1016.  
  1017.     W3D_Driver **drivers = W3D_GetDrivers();
  1018.  
  1019.     if (*drivers == NULL) {
  1020.         printf("Panic: No Drivers found\n");
  1021.         return;
  1022.     }
  1023.     printf("Available drivers:\n");
  1024.     while (*drivers) {
  1025.         printf("%s\n\tSupports format 0x%lX\n\t",
  1026.             drivers[0]->name, drivers[0]->formats);
  1027.         if (drivers[0]->swdriver) printf("CPU Driver\n");
  1028.         else                      printf("Hardware Driver\n");
  1029.  
  1030.         printf("\tPrimitives supported:\n\t");
  1031.         res = W3D_QueryDriver(drivers[0], W3D_Q_DRAW_POINT, W3D_FMT_R5G5B5);
  1032.         if (res != W3D_NOT_SUPPORTED) printf("[POINT] ");
  1033.  
  1034.         res = W3D_QueryDriver(drivers[0], W3D_Q_DRAW_LINE, W3D_FMT_R5G5B5);
  1035.         if (res != W3D_NOT_SUPPORTED) printf("[LINE] ");
  1036.  
  1037.         res = W3D_QueryDriver(drivers[0], W3D_Q_DRAW_TRIANGLE, W3D_FMT_R5G5B5);
  1038.         if (res != W3D_NOT_SUPPORTED) printf("[TRIANGLE] ");
  1039.  
  1040.         printf("\n\tFiltering:\n\t");
  1041.         res = W3D_QueryDriver(drivers[0], W3D_Q_BILINEARFILTER, W3D_FMT_R5G5B5);
  1042.         if (res != W3D_NOT_SUPPORTED) printf("[BI-FILTER] ");
  1043.  
  1044.         res = W3D_QueryDriver(drivers[0], W3D_Q_MMFILTER, W3D_FMT_R5G5B5);
  1045.         if (res != W3D_NOT_SUPPORTED) printf("[MM-FILTER] ");
  1046.         printf("\n");
  1047.  
  1048.         drivers++;
  1049.     }
  1050.     printf("\n\n");
  1051. }
  1052. //-
  1053. //+ main
  1054. void main(int argc, char **argv)
  1055. {
  1056.     ULONG ModeID, ID, format;
  1057.     ULONG OpenErr, CError, res, ret;
  1058.     struct BitMap *bm = NULL;
  1059.     W3D_Context *context = NULL;
  1060.     BOOL running=TRUE, clip = FALSE;
  1061.     struct IntuiMessage *imsg;
  1062.     int i,j,k;
  1063.     ULONG flags;
  1064.     int update;
  1065.     float f;
  1066.     UBYTE *newm;
  1067.     UBYTE *hit = 0;
  1068.     int si;
  1069.     LONG repeat;
  1070.     W3D_Scissor s = {0, 0, 640, 480};
  1071.     W3D_Scissor sc = {32, 32, 64, 64};
  1072.  
  1073.     rda = (struct RDArgs *)AllocDosObject(DOS_RDARGS, NULL);
  1074.     bzero(result, 40);
  1075.     if (rda) {
  1076.         rda->RDA_Source.CS_Buffer = NULL;
  1077.         ReadArgs(TEMPLATE, result, rda);
  1078.         FreeDosObject(DOS_RDARGS, rda);
  1079.     }
  1080.  
  1081.     if (result[2]) repeat = *((LONG *)result[2]);
  1082.     else           repeat = 1;
  1083.  
  1084.     // Initialize the required libraries
  1085.     CyberGfxBase = OpenLibrary("cybergraphics.library", 0L);
  1086.     if (!CyberGfxBase) {
  1087.         printf("Error opening CyberGraphX library\n");
  1088.         goto panic;
  1089.     }
  1090.  
  1091. #ifndef __PPC__
  1092.     Warp3DBase = OpenLibrary("Warp3D.library", 2L);
  1093.     if (!Warp3DBase) {
  1094.         printf("Error opening Warp3D library\n");
  1095.         goto panic;
  1096. #else
  1097.     Warp3DPPCBase = OpenLibrary("Warp3DPPC.library", 2L);
  1098.     if (!Warp3DPPCBase) {
  1099.         printf("Error opening Warp3DPPC.library\n");
  1100. #endif
  1101.     }
  1102.  
  1103.     // Check for availability of drivers
  1104.     flags = W3D_CheckDriver();
  1105.     if (flags & W3D_DRIVER_3DHW) printf("Hardware driver available\n");
  1106.     if (flags & W3D_DRIVER_CPU)  printf("Software driver available\n");
  1107.     if (flags & W3D_DRIVER_UNAVAILABLE) {
  1108.         printf("PANIC: no driver available!!!\n");
  1109.         goto panic;
  1110.     }
  1111.  
  1112.     PrintDriverInfo();
  1113.  
  1114.     // Get a screen mode
  1115.     // Due to the current limitations of the virge, this
  1116.     // Screen must be 15 bit deep (NOT 16!)
  1117. #if 0
  1118.     ModeID = BestCModeIDTags(
  1119.         CYBRBIDTG_Depth,            15L,
  1120.         CYBRBIDTG_NominalWidth,     640,
  1121.         CYBRBIDTG_NominalHeight,    480,
  1122.         CYBRBIDTG_BoardName,        "CVision3D",
  1123.     TAG_DONE);
  1124. #else
  1125.     /*
  1126.     ** New in V2: The Screenmode requester
  1127.     ** This requester will ask for any screenmode the installed
  1128.     ** Hardware driver can handle, and also restrict the presented
  1129.     ** screen modes to 640x480 Modes...
  1130.     */
  1131.     ModeID = W3D_RequestModeTags(
  1132.         W3D_SMR_TYPE,       W3D_DRIVER_3DHW,
  1133.         W3D_SMR_SIZEFILTER, TRUE,
  1134.         W3D_SMR_DESTFMT,    ~W3D_FMT_CLUT,
  1135.         ASLSM_MinWidth,     640,
  1136.         ASLSM_MaxWidth,     641,
  1137.         ASLSM_MinHeight,    480,
  1138.         ASLSM_MaxHeight,    481,
  1139.     TAG_DONE);
  1140. #endif
  1141.  
  1142.     if (ModeID == INVALID_ID) {
  1143.         printf("Error: No ModeID found\n");
  1144.         goto panic;
  1145.     }
  1146.  
  1147.     // Open Screen
  1148.     screen = OpenScreenTags(NULL,
  1149.         SA_Height,    960,
  1150.         SA_DisplayID, ModeID,
  1151.         SA_Depth,     8,
  1152.         SA_ErrorCode, &OpenErr,
  1153.         SA_ShowTitle, FALSE,
  1154.         SA_Draggable, FALSE,
  1155.     TAG_DONE);
  1156.  
  1157.     if (!screen) {
  1158.         printf("Unable to open screen. Reason: Error code %d\n", OpenErr);
  1159.         goto panic;
  1160.     }
  1161.  
  1162.     // Open window
  1163.     // While this is not strictly nessessary, we use it because
  1164.     // we want to get IDCMP messages. You can also use the screen's
  1165.     // bitmap to render
  1166.     window = OpenWindowTags(NULL,
  1167.         WA_CustomScreen,    screen,
  1168.         WA_Activate,        TRUE,
  1169.         WA_Width,           screen->Width,
  1170.         WA_Height,          screen->Height,
  1171.         WA_Left,            0,
  1172.         WA_Top,             0,
  1173.         WA_Title,           NULL,
  1174.         WA_CloseGadget,     FALSE,
  1175.         WA_Backdrop,        TRUE,
  1176.         WA_Borderless,      TRUE,
  1177.         WA_IDCMP,           IDCMP_CLOSEWINDOW|IDCMP_VANILLAKEY|IDCMP_RAWKEY|IDCMP_MOUSEBUTTONS|IDCMP_MOUSEMOVE|IDCMP_DELTAMOVE,
  1178.         WA_Flags,           WFLG_REPORTMOUSE|WFLG_RMBTRAP,
  1179.     TAG_DONE);
  1180.  
  1181.     SetRGB32(&(screen->ViewPort), 0, 0x40ffffff, 0x40ffffff, 0x88ffffff);
  1182.     SetRGB32(&(screen->ViewPort), 10, 0xffffffff, 0x0, 0x0);
  1183.  
  1184.     if (!window) {
  1185.         printf("Unable to open window.\n");
  1186.         goto panic;
  1187.     }
  1188.  
  1189.     // We want to use this bitmap
  1190.     bm = window->RPort->BitMap;
  1191.  
  1192.     SetAPen(window->RPort, 249);
  1193.     RectFill(window->RPort, 0, 0, 639, 959);
  1194.  
  1195.     // Go ahead and create the context. We need a context for every drawing
  1196.     // operation, so this is done quite early in the program.
  1197.     // NOTE: Some functions, like W3D_Query, do work without a context.
  1198.     // The W3D_Query function without a context can be used to determine
  1199.     // what kind of display/texture format the chip driver prefers.
  1200.  
  1201.     context = W3D_CreateContextTags(&CError,
  1202.         W3D_CC_MODEID,      ModeID,             // Mandatory for non-pubscreen
  1203.         W3D_CC_BITMAP,      bm,                 // The bitmap we'll use
  1204.         W3D_CC_YOFFSET,     0,                  // We don't do dbuffering
  1205.         W3D_CC_DRIVERTYPE,  W3D_DRIVER_BEST,    // Let Warp3D decide
  1206.         W3D_CC_DOUBLEHEIGHT,TRUE,               // Double height screen
  1207.         W3D_CC_FAST,        TRUE,               // Fast drawing
  1208.     TAG_DONE);
  1209.  
  1210.     if (!context || CError != W3D_SUCCESS) {
  1211.         printf("Error creating context. Reason:");
  1212.         switch(CError) {
  1213.         case W3D_ILLEGALINPUT:
  1214.             printf("Illegal input to CreateContext function\n");
  1215.             break;
  1216.         case W3D_NOMEMORY:
  1217.             printf("Out of memory\n");
  1218.             break;
  1219.         case W3D_NODRIVER:
  1220.             printf("No suitable driver found\n");
  1221.             break;
  1222.         case W3D_UNSUPPORTEDFMT:
  1223.             printf("Supplied bitmap cannot be handled by Warp3D\n");
  1224.             break;
  1225.         case W3D_ILLEGALBITMAP:
  1226.             printf("Supplied bitmap not properly initialized\n");
  1227.             break;
  1228.         default:
  1229.             printf("An error has occured... gosh\n");
  1230.         }
  1231.         goto panic;
  1232.     }
  1233.  
  1234.     if (result[0]) {
  1235.         if (FALSE == GenTexture(context, (char *)result[0], repeat)) {
  1236.             printf("Error loading/generating texture\n");
  1237.             goto panic;
  1238.         }
  1239.     } else {
  1240.         if (FALSE == GenTexture(context, "wall.ppm", repeat)) {
  1241.             printf("Error loading/generating default texture\n");
  1242.             goto panic;
  1243.         }
  1244.     }
  1245.  
  1246.     if (result[3]) {
  1247.         if (FALSE == GenLightmap(context, (char *)result[3], repeat)) {
  1248.             printf("Error loading/generating lightmap\n");
  1249.             goto panic;
  1250.         }
  1251.     }
  1252.  
  1253.  /* If you need to know the "success" of setting a state, you can
  1254.     find out by examining the return value of W3D_SetState. This should
  1255.     be done if your program depends heavily on this feature. If not, you
  1256.     may safely ignore the result. For example, the W3D_DITHERING state
  1257.     might not have a large impact on the performance of your engine, so
  1258.     you might ignore the outcome. On the other hand, it might be a severe
  1259.     problem if your driver does not support texture mapping.
  1260.  
  1261.     Things like this can be verified with W3D_Query after the context was
  1262.     created, or with W3D_QueryDriver if you didn't create a context yet.
  1263.  */
  1264.  
  1265.     if ( W3D_SetState(context, W3D_SCISSOR, W3D_ENABLE) == W3D_UNSUPPORTEDSTATE) {
  1266.         printf("Scissoring not supported. Proceeding with fingers crossed\n");
  1267.     }
  1268.  
  1269.     // Set dithering. This will look considerably better on 15 bit displays.
  1270.     W3D_SetState(context, W3D_DITHERING, W3D_ENABLE);
  1271.  
  1272.     // Set texture wrapping mode to on.
  1273.     // Read the section about limitations of the Virge for this
  1274.     W3D_SetWrapMode(context, tex, W3D_REPEAT, W3D_REPEAT, NULL);
  1275.     // Set blending to CurrentBlend mode (defaults to no alpha blending)
  1276.     W3D_SetTexEnv(context, tex, BlendModes[CurrentBlend], NULL);
  1277.     // Set Fog parameters
  1278.     W3D_SetFogParams(context, &myFog, FogModes[CurrentFog]);
  1279.     // Set Texture mapping
  1280.     W3D_SetState(context, W3D_TEXMAPPING, W3D_ENABLE);
  1281.     // Set Drawing region
  1282.     W3D_SetDrawRegion(context, bm, 0, &s);
  1283.     // Set current color
  1284.     W3D_SetCurrentColor(context, &ccol);
  1285.     if (result[1]) {
  1286.         // Set ZBuffer modes
  1287.         if (W3D_SUCCESS != W3D_AllocZBuffer(context)) {
  1288.             printf("Error: Can`t create ZBuffer\nZBuffering will not be available\n");
  1289.         } else {
  1290.             zb = TRUE;
  1291.             W3D_SetState(context, W3D_ZBUFFERUPDATE, W3D_ENABLE);
  1292.             W3D_ClearZBuffer(context, &zdepth);
  1293.         }
  1294.     }
  1295.  
  1296.     // Clear window, then draw our first wall.
  1297.     ClearWindow(context, window);
  1298.     DrawWall(context);
  1299.  
  1300.     running=TRUE;
  1301.  
  1302.     while (running) {
  1303. //        WaitPort(window->UserPort);
  1304.         while (imsg = (struct IntuiMessage *)GetMsg(window->UserPort)) {
  1305.             if (imsg == NULL) break;
  1306.             switch(imsg->Class) {
  1307.             case IDCMP_MOUSEBUTTONS:
  1308.                 if (imsg->Code == SELECTDOWN) {
  1309.                     drag = 1;
  1310.                 }
  1311.                 if (imsg->Code == SELECTUP) {
  1312.                     drag = 0;
  1313.                 }
  1314.                 if (imsg->Code == MENUDOWN) {
  1315.                     push = 1;
  1316.                 }
  1317.                 if (imsg->Code == MENUUP) {
  1318.                     push = 0;
  1319.                 }
  1320.                 break;
  1321.             case IDCMP_MOUSEMOVE:
  1322.                 if (drag) {
  1323.                     theta += (float)(imsg->MouseX);
  1324.                     if (theta < 0.0) theta += 360.f;
  1325.                     if (theta > 360.0) theta -= 360.f;
  1326.                 }
  1327.                 if (push) {
  1328.                     Pos.z += (float)(imsg->MouseY)/128.f;
  1329.                     if (Pos.z < Front+1.f) Pos.z = Front+1.f;
  1330.                     if (Pos.z > Back-1.f) Pos.z = Back-1.f;
  1331.                 }
  1332.                 update = 1;
  1333.                 break;
  1334.             case IDCMP_CLOSEWINDOW:
  1335.                 running=FALSE;
  1336.                 break;
  1337.             case IDCMP_RAWKEY:
  1338.                 update=1;
  1339.                 if (cflag == 0) {
  1340.                     switch(imsg->Code) {
  1341.                     case 0x4F:
  1342.                         theta -= 4.f;
  1343.                         if (theta < 0.0) theta += 360.f;
  1344.                         break;
  1345.                     case 0x4e:
  1346.                         theta += 4.f;
  1347.                         if (theta > 360.0) theta -= 360.f;
  1348.                         break;
  1349.                     case 0x4C:
  1350.                         Pos.z -= 1.f;
  1351.                         if (Pos.z < Front+1.f) Pos.z = Front+1.f;
  1352.                         break;
  1353.                     case 0x4D:
  1354.                         Pos.z += 1.f;
  1355.                         if (Pos.z > Back-1.f) Pos.z = Back-1.f;
  1356.                         break;
  1357.                     case 0x50:
  1358.                         W3D_SetWrapMode(context, tex, W3D_CLAMP, W3D_CLAMP, NULL);
  1359.                         break;
  1360.                     case 0x51:
  1361.                         W3D_SetWrapMode(context, tex, W3D_REPEAT, W3D_REPEAT, NULL);
  1362.                         break;
  1363.                     case 0x5f:      // Debug key
  1364.                         clip = !clip;
  1365.                         break;
  1366.                     break;
  1367.                     }
  1368.                 } else {
  1369.                     switch(imsg->Code) {
  1370.                     case 0x4F:
  1371.                         theta -= 1.f;
  1372.                         if (theta < 0.0) theta += 360.f;
  1373.                         break;
  1374.                     case 0x4e:
  1375.                         theta += 1.f;
  1376.                         if (theta > 360.0) theta -= 360.f;
  1377.                         break;
  1378.                     case 0x4C:
  1379.                         Pos.z -= 0.25f;
  1380.                         if (Pos.z < Front+1.f) Pos.z = Front+1.f;
  1381.                         break;
  1382.                     case 0x4D:
  1383.                         Pos.z += 0.25f;
  1384.                         if (Pos.z > Back-1.f) Pos.z = Back-1.f;
  1385.                         break;
  1386.                     }
  1387.                 }
  1388.                 break;
  1389.             case IDCMP_VANILLAKEY:
  1390.                 update = 1;
  1391.                 switch(imsg->Code) {
  1392.                 case '|':
  1393.                     newm = LoadTextureFromPPM((APTR)NULL, (char *)"smallugly.ppm", 30, &si, &si);
  1394.                     W3D_UpdateTexSubImage(context, tex, (void *)newm, 0, NULL, &sc, 0);
  1395.                     FreeVec(newm);
  1396.                     break;
  1397.                 case 'S':
  1398.                     second_wall = 1 - second_wall;
  1399.                     break;
  1400.                 case '8':   // Move fog end further back
  1401.                     myFog.fog_end -= 0.01;
  1402.                     if (myFog.fog_end < 0.05) myFog.fog_end = 0.05;
  1403.                     W3D_SetFogParams(context, &myFog, FogModes[CurrentFog]);
  1404.                     break;
  1405.                 case '5':   // Move fog end forward
  1406.                     myFog.fog_end += 0.01;
  1407.                     if (myFog.fog_end+0.05 > myFog.fog_start) myFog.fog_end = myFog.fog_start-0.05;
  1408.                     W3D_SetFogParams(context, &myFog, FogModes[CurrentFog]);
  1409.                     break;
  1410.                 case '9':   // Move fog start further back
  1411.                     myFog.fog_start -= 0.01;
  1412.                     if (myFog.fog_start-0.05 < myFog.fog_end) myFog.fog_start = myFog.fog_end+0.05;
  1413.                     W3D_SetFogParams(context, &myFog, FogModes[CurrentFog]);
  1414.                     break;
  1415.                 case '6':   // Move fog start forward
  1416.                     myFog.fog_start += 0.01;
  1417.                     if (myFog.fog_start > 1.0) myFog.fog_start = 1.0;
  1418.                     W3D_SetFogParams(context, &myFog, FogModes[CurrentFog]);
  1419.                     break;
  1420.                 case 'F': // Toggle fog quality
  1421.                     if (FogQuality == W3D_H_NICE) FogQuality = W3D_H_FAST;
  1422.                     else                          FogQuality = W3D_H_NICE;
  1423.                     W3D_Hint(context, W3D_H_FOGGING, FogQuality);
  1424.                     break;
  1425.                 case 't':
  1426.                 case 'T':   // Toggle texture mapping
  1427.                     if (W3D_GetState(context, W3D_TEXMAPPING) == W3D_ENABLED)
  1428.                         W3D_SetState(context, W3D_TEXMAPPING, W3D_DISABLE);
  1429.                     else
  1430.                         W3D_SetState(context, W3D_TEXMAPPING, W3D_ENABLE);
  1431.                     break;
  1432.                 case 'p':
  1433.                 case 'P':   // Toggle perspective mapping
  1434.                     if (forcelin == 1) break; // Exit if forced to linear
  1435.                     if (persp==0) persp=1;
  1436.                     else          persp=0;
  1437.                     if (persp) W3D_SetState(context, W3D_PERSPECTIVE, W3D_ENABLE);
  1438.                     else       W3D_SetState(context, W3D_PERSPECTIVE, W3D_DISABLE);
  1439.                     break;
  1440.                 case '1':
  1441.                     curfilt = 1;
  1442.                     ret = W3D_SetFilter(context, tex, W3D_NEAREST, W3D_NEAREST);
  1443.                     if (ret != W3D_SUCCESS) printf("Warning: Unsupported Filter mode\n");
  1444.                     if (lighttex) W3D_SetFilter(context, tex, W3D_NEAREST, W3D_NEAREST);
  1445.                     break;
  1446.                 case '2':
  1447.                     curfilt = 2;
  1448.                     ret = W3D_SetFilter(context, tex, W3D_LINEAR, W3D_LINEAR);
  1449.                     if (ret != W3D_SUCCESS) printf("Warning: Unsupported Filter mode\n");
  1450.                     if (lighttex) W3D_SetFilter(context, tex, W3D_LINEAR, W3D_LINEAR);
  1451.                     break;
  1452.                 case '3':
  1453.                     curfilt = 3;
  1454.                     ret = W3D_SetFilter(context, tex, W3D_NEAREST_MIP_NEAREST, W3D_NEAREST);
  1455.                     if (ret != W3D_SUCCESS) printf("Warning: Unsupported Filter mode\n");
  1456.                     if (lighttex) W3D_SetFilter(context, tex, W3D_NEAREST_MIP_NEAREST, W3D_NEAREST);
  1457.                     break;
  1458.                 case '4':
  1459.                     curfilt = 4;
  1460.                     ret = W3D_SetFilter(context, tex, W3D_LINEAR_MIP_LINEAR, W3D_LINEAR);
  1461.                     if (ret != W3D_SUCCESS) printf("Warning: Unsupported Filter mode\n");
  1462.                     if (lighttex) W3D_SetFilter(context, tex, W3D_LINEAR_MIP_LINEAR, W3D_LINEAR);
  1463.                     break;
  1464.                 case 'a':
  1465.                 case 'A':   // Toggle "Show mipmaps" (A Flag)
  1466.                     #ifndef STORM   // Something;s wrong with the cgx includes
  1467.                     aflag = 1-aflag;
  1468.                     #endif
  1469.                     break;
  1470.                 case 'b':
  1471.                 case 'B':   // Toggle "Show coordinates" (B Flag)
  1472.                     bflag = 1-bflag;
  1473.                     break;
  1474.                 case 'c':
  1475.                 case 'C':   // Toggle "Slowmotion" (C FLag)
  1476.                     cflag = 1-cflag;
  1477.                     break;
  1478.                 case 'd':
  1479.                 case 'D':
  1480.                     dflag = 1-dflag;
  1481.                     break;
  1482.                 case 'e':
  1483.                 case 'E':   // Toggle Lighting
  1484.                     do {
  1485.                         CurrentBlend = (CurrentBlend+1)%4;
  1486.                         res = W3D_SetTexEnv(context, tex, BlendModes[CurrentBlend], NULL);
  1487.                     } while (res != W3D_SUCCESS);
  1488.                     break;
  1489.                 case 'f': // Toggle fog. Note we ignore success/failure
  1490.                     do {
  1491.                         CurrentFog = (CurrentFog+1)%5;
  1492.                         if (CurrentFog == 0) {
  1493.                             res = W3D_SetState(context, W3D_FOGGING, W3D_DISABLE);
  1494.                         } else {
  1495.                             res = W3D_SetFogParams(context, &myFog, FogModes[CurrentFog]);
  1496.                             if (res == W3D_SUCCESS)
  1497.                                 W3D_SetState(context, W3D_FOGGING, W3D_ENABLE);
  1498.                         }
  1499.                     } while (res != W3D_SUCCESS);
  1500.                     break;
  1501.                 case 'o':
  1502.                 case 'O':
  1503.                     outline = ~outline;
  1504.                     break;
  1505.                 case 'z':
  1506.                 case 'Z':   // Toggle ZBuffer. Currently not supported
  1507.                     zmode++; if (zmode == 9) zmode=0;
  1508.                     if (zmode==0) {
  1509.                         W3D_SetState(context, W3D_ZBUFFER, W3D_DISABLE);
  1510.                     } else {
  1511.                         W3D_SetState(context, W3D_ZBUFFER, W3D_ENABLE);
  1512.                         if (W3D_DISABLED == W3D_GetState(context, W3D_ZBUFFER)) {
  1513.                             printf("Warning: Can`t enable ZBuffer\n");
  1514.                         }
  1515.                         W3D_SetZCompareMode(context, zmode);
  1516.                     }
  1517.                     break;
  1518.                 case 'L':
  1519.                     if (W3D_GetState(context, W3D_GOURAUD) == W3D_ENABLED)
  1520.                         W3D_SetState(context, W3D_GOURAUD, W3D_DISABLE);
  1521.                     else
  1522.                         W3D_SetState(context, W3D_GOURAUD, W3D_ENABLE);
  1523.                     break;
  1524.                 case 'l':   // Toggle Alpha Blending
  1525.                     W3D_SetBlendMode(context, W3D_SRC_ALPHA, W3D_ONE_MINUS_SRC_ALPHA);
  1526.                     if (W3D_GetState(context, W3D_BLENDING) == W3D_ENABLED)
  1527.                         W3D_SetState(context, W3D_BLENDING, W3D_DISABLE);
  1528.                     else
  1529.                         W3D_SetState(context, W3D_BLENDING, W3D_ENABLE);
  1530.                     break;
  1531.                 case 's':
  1532.                     if (W3D_GetState(context, W3D_FAST) == W3D_ENABLED)
  1533.                         W3D_SetState(context, W3D_FAST, W3D_DISABLE);
  1534.                     else
  1535.                         W3D_SetState(context, W3D_FAST, W3D_ENABLE);
  1536.                     break;
  1537.                 case '+':
  1538.                     zdepth+=0.05;
  1539.                     if (zdepth>1.0) zdepth=1.0;
  1540.                     W3D_ClearZBuffer(context, &zdepth);
  1541.                     break;
  1542.                 case '-':
  1543.                     zdepth-=0.05;
  1544.                     if (zdepth<0.0) zdepth=0.0;
  1545.                     W3D_ClearZBuffer(context, &zdepth);
  1546.                     break;
  1547.                 case 27:    // Esc or 'Q' quits
  1548.                 case 'Q':
  1549.                     running=FALSE;
  1550.                     break;
  1551.                 case 13:
  1552.                     {
  1553.                     W3D_Double test;
  1554.                     W3D_ReadZPixel(context, 10, 10, &test);
  1555.                     printf("Test: %g\n", (double)test);
  1556.                     }
  1557.                     break;
  1558.                 default:
  1559.                     break;
  1560.                 }
  1561.             break;
  1562.             }
  1563.  
  1564.             if (imsg) {
  1565.                 ReplyMsg((struct Message *)imsg);
  1566.                 imsg = NULL;
  1567.             }
  1568.         }
  1569.         SwitchBuffer(context, bm, screen, clip);
  1570.         ClearWindow(context, window);
  1571.         DrawWall(context);
  1572.         if (zb && W3D_SUCCESS == W3D_LockHardware(context)) {
  1573.             W3D_ClearZBuffer(context, &zdepth);
  1574.             W3D_UnLockHardware(context);
  1575.         }
  1576.     }
  1577.  
  1578. panic:
  1579.     printf("Closing down...\n");
  1580.     if (context)        W3D_FreeZBuffer(context);
  1581.     if (tex)            W3D_FreeTexObj(context, tex);
  1582.     if (lighttex)       W3D_FreeTexObj(context, lighttex);
  1583.     if (context)        W3D_DestroyContext(context);
  1584.     if (texmap)         FreeVec(texmap);
  1585.     if (window)         CloseWindow(window);
  1586.     if (screen)         CloseScreen(screen);
  1587. #ifndef __PPC__
  1588.     if (Warp3DBase)     CloseLibrary(Warp3DBase);
  1589. #else
  1590.     if (Warp3DPPCBase)  CloseLibrary(Warp3DPPCBase);
  1591. #endif
  1592.     if (CyberGfxBase)   CloseLibrary(CyberGfxBase);
  1593.     exit(0);
  1594. }
  1595. //-
  1596.